This document demonstrates how to use the leaflet package to create interactive web maps and use animated transitions to enhance visual storytelling.
Code
# Function to quietly install and load packagesquiet_library <-function(pkg) {suppressMessages(suppressWarnings({if (!requireNamespace(pkg, quietly =TRUE)) {install.packages(pkg, quiet =TRUE) # Install without messages }library(pkg, character.only =TRUE) # Load silently }))}quiet_library("ggplot2")quiet_library("sf") # For handling spatial dataquiet_library("ggspatial") # Facilitates adding map elements to ggplot2quiet_library("rnaturalearth") # Provides world map dataquiet_library("rnaturalearthdata") quiet_library("geojsonio") # For reading geo json dataquiet_library("leaflet") # For interactivity in mapsquiet_library("magick") # For swipequiet_library("tidyverse")quiet_library("viridisLite") # for consistent viridis palettequiet_library("geosphere") # For adding a routemydata <-file.path("C:","Datasets")
Base Map
Code
# setup the data for Irelandireland <- rnaturalearth::ne_countries(scale ="medium", country ="Ireland", returnclass ="sf")# Setup dataframe with longitude and latitude of major citiescities <-data.frame(name =c("Dublin", "Cork", "Limerick", "Galway"),lon =c(-6.2603, -8.472, -8.6305, -9.0568),lat =c(53.3498, 51.8985, 52.6680, 53.2707))# Using the shape data downloaded from # Replace this with your actual file pathjson_file <-file.path(mydata, "gadm41_IRL_1.json")# Read the GeoJSON file into an sf objectcountyshapes <- sf::st_read(json_file)
Reading layer `gadm41_IRL_1' from data source `C:\datasets\gadm41_IRL_1.json' using driver `GeoJSON'
Simple feature collection with 26 features and 11 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: -10.6628 ymin: 51.4199 xmax: -5.9945 ymax: 55.4351
Geodetic CRS: WGS 84
Code
# Replace NAME_1 with "Cork" where VARNAME_1 is "Corcaigh"# For some reason some Cork data is NA for NAME_1 but has the Irish equivalencountyshapes$NAME_1[countyshapes$VARNAME_1 =="Corcaigh"] <-"Cork"# Read in a file from CSO data of median income per electoral regionincomeloc <-file.path(mydata,"MedianIncomeIreland.csv" )countyincome <-read.csv(incomeloc) # Using a regular expression, extract county name after "Co." or Ending with Dublin, Cork City or Tipperary and add to the same dataset as column countycountyincome$county <- stringr::str_extract(countyincome$Electoral.Division, "(?<=Co\\. )\\w+|Dublin$|Cork City$|Tipperary$")# Regular Expression explanation:# (?<=Co\. )\w+ - This is a lookbehind (?<=...), which ensures that the match only occurs if it is preceded by "Co. " (e.g., "Co. Mayo").# \w+ matches one or more word characters (letters, numbers, or underscores), so it captures county names like "Mayo", "Galway", etc., after "Co. ".# The | means OR.# Dublin$ matches "Dublin" only if it appears at the end of the string ($ means end of the string).# Cork City$ Matches "Cork City" only if it appears at the end of the string.# Tipperary$ Matches "Tipperary" only if it appears at the end of the string.# Replace Cork City by Corkcountyincome <- countyincome %>%mutate(county =case_when( county =="Cork City"~"Cork",TRUE~ county ))# Rename column "VALUE" to "avg_income"countyincome <- countyincome %>%rename(mdn_income = VALUE)countyincome <-na.omit(countyincome)# Summarize avg_income by county_name, omitting nassummary_df <-na.omit(countyincome) %>%group_by(county) %>%summarize(mdn_income =median(mdn_income, na.rm =TRUE))# Merge income data with spatial county boundariescounties_income <- countyshapes %>%inner_join(summary_df, by =c("NAME_1"="county")) %>%# Ensure column names matchst_as_sf() # Ensure it remains a spatial object with geometry# Define a new projection (Irish Traverse Mercator)crs_itransm <-2157# Reproject all spatial dataireland_proj <- sf::st_transform(ireland, crs_itransm)counties_proj <- sf::st_transform(countyshapes, crs_itransm)counties_income_proj <- sf::st_transform(counties_income, crs_itransm)# Convert city coordinates to projected CRScities_proj <- cities %>% sf::st_as_sf(coords =c("lon", "lat"), crs =2157) %>% sf::st_transform(crs_itransm) %>% sf::st_coordinates() %>%as.data.frame() %>%mutate(name = cities$name) # Plot using the new projectionmap1 <- ggplot2::ggplot() +geom_sf(data = ireland_proj, fill ="lightgreen", color ="darkblue") +# County shapesgeom_sf(data = counties_proj, fill =NA, color ="red", size =0.5) +# Citiesgeom_point(data = cities_proj, aes(x = X, y = Y), color ="red", size =3) +geom_text(data = cities_proj, aes(x = X, y = Y, label = name), vjust =-1) +# Add a curved line from Dublin to Galwaygeom_curve(aes(x =-6.2603, y =53.3498, xend =-9.0568, yend =53.2707),curvature =0.2, color ="purple", linewidth =1, arrow =arrow(length =unit(0.15, "inches"))) +# Scale bar and compasannotation_scale(location ="bl", width_hint =0.5, unit_category ="metric", bar_cols =c("darkblue", "white")) +annotation_north_arrow(location ="tl", which_north ="true", style = north_arrow_fancy_orienteering) +theme_minimal() +ggtitle("Map of Ireland (ITM Projection)")# Add income levelsmap2 <- ggplot2::ggplot() +geom_sf(data = ireland_proj, fill ="lightgreen", color ="darkblue") +# County shapesgeom_sf(data = counties_proj, fill =NA, color ="red", size =0.5) +# Median incomegeom_sf(data = counties_income_proj, aes(fill = mdn_income), color ="gold") +scale_fill_viridis_c(name ="Median Income (€)", na.value ="grey50") +# Citiesgeom_point(data = cities_proj, aes(x = X, y = Y), color ="red", size =3) +geom_text(data = cities_proj, aes(x = X, y = Y, label = name), vjust =-1) +# Add a curved line from Dublin to Galwaygeom_curve(aes(x =-6.2603, y =53.3498, xend =-9.0568, yend =53.2707),curvature =0.2, color ="purple", linewidth =1, arrow =arrow(length =unit(0.15, "inches"))) +# Scale bar and compasannotation_scale(location ="bl", width_hint =0.5, unit_category ="metric", bar_cols =c("darkblue", "white")) +annotation_north_arrow(location ="tl", which_north ="true", style = north_arrow_fancy_orienteering) +theme_minimal() +ggtitle("Median Income by County in Ireland (ITM Projection)")map1
Code
# Save as PNGggsave("ireland_map.png", plot = map1, width =10, height =8, dpi =300)# Save as PNGggsave("ireland_income_map.png", plot = map2, width =10, height =8, dpi =300)